﻿/*
 * 
 * User: Gavin Mead
 * Date: 11/25/2009
 * Time: 4:01 PM
 * 
 * 
 */

using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

using GraphLibrary;

namespace GraphLibraryTests
{
    [TestFixture]
    public class DirectedGraphTests
    {
        
        private IGraph<int, int> DirectedGraph()
        {
            return GraphFactory<int, int>.CreateGraph(GraphTypes.Directed);
        }
        
        [Test]
        [Description("Verifies that an exception is thrown " +
                     "when either AddEdge(.,IVertexIds) are " +
                     "null.")]
        public void NullIVertexIdsAddEdgeTest()
        {
            IGraph<int,int> graph = DirectedGraph();
            
            ArgumentNullException ex1 = Assert.Throws<ArgumentNullException>(delegate {
                                                                                 graph.AddEdge(default(int), null,null);
                                                                             });
            
            ArgumentNullException ex2 = Assert.Throws<ArgumentNullException>(delegate {
                                                                                 graph.AddEdge(default(int), new BaseVertexId(), null);
                                                                             });
            
            ArgumentNullException ex3 = Assert.Throws<ArgumentNullException>(delegate {
                                                                                 graph.AddEdge(default(int), null, new BaseVertexId());
                                                                             });
            
            Assert.NotNull(ex1);
            Assert.NotNull(ex2);
            Assert.NotNull(ex3);
                                                                                                                                             
        }
        
        [Test]
        [Description("Verifies that an exception is thrown " +
                     "when either AddEdge(.,IVertexIds) are " +
                     " not found")]
        public void UnknownIVertexIdsAddEdgeTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId goodId = graph.AddVertex(35);
            IVertexId badId = new BaseVertexId();
            
            String expectedMessage1 = "One or more vertices could not be found.";
            
            ArgumentException ex1 = Assert.Throws<ArgumentException>(delegate {
                                                                         graph.AddEdge(default(int), goodId, badId);
                                                                     });
            
            ArgumentException ex2 = Assert.Throws<ArgumentException>(delegate {
                                                                         graph.AddEdge(default(int), badId, goodId);
                                                                     });
            
            Assert.NotNull(ex1);
            Assert.NotNull(ex2);
            Assert.AreEqual(expectedMessage1, ex1.Message);
            Assert.AreEqual(expectedMessage1, ex2.Message);
        }

        [Test]
        [Description("Verifies that an exception is thrown " +
                     "when an attempt a second call to AddEdge " +
                     "with the same IVertexIds.")]
        public void GraphExceptionAddEdgeTest()
        {
            String expectedMessage = "A directed graph can only have one directed edge going " +
                                     "from vertex 1 to vertex 2.";
            
            IGraph<int, int> graph = DirectedGraph();
            IVertexId goodId1 = graph.AddVertex(35);
            IVertexId goodId2 = graph.AddVertex(35);
            
            IEdgeId id = graph.AddEdge(default(int), goodId1, goodId2);
            
            GraphException ex = Assert.Throws<GraphException>(delegate {
                                                                  IEdgeId id2 = graph.AddEdge(default(int), goodId1,
                                                                                              goodId2);
                                                              });
            
            Assert.NotNull(ex);
            Assert.AreEqual(expectedMessage, ex.Message);
        }
        
        [Test]
        [Description("Verifies that undirected graph " +
                     "is allowed")]
        public void GraphUndirectedEdgeTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId goodId1 = graph.AddVertex(35);
            IVertexId goodId2 = graph.AddVertex(30);
            
            IEdgeId eid1 = graph.AddEdge(default(int),goodId1, goodId2);
            IEdgeId eid2 = graph.AddEdge(default(int),goodId2, goodId1);
            
            //doesn't throw an exception.
            Assert.True(true);
        }
        
        [Test]
        [Description("Verifies that a new edge is created, and that all " +
                     "data can be retrieved.")]
        public void AddEdgeTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId edgeId = graph.AddEdge(5, 1, 2);
            
            int vertex1 = graph.GetVertexData(edgeId.Vertex1Id);
            int vertex2 = graph.GetVertexData(edgeId.Vertex2Id);
            int edgeData = graph.GetEdgeData(edgeId);
            
            Assert.AreEqual(5, edgeData);
            Assert.AreEqual(1, vertex1);
            Assert.AreEqual(2, vertex2);
        }
        
        [Test]
        [Description("Verifies that existing vertexIds are associated " +
                     "with a valid edgeId when adding an edge")]
        public void AddEdgeWithExistingVerticesTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId id1 = graph.AddVertex(5);
            IVertexId id2 = graph.AddVertex(1);
            
            IEdgeId edgeId = graph.AddEdge(default(int), id1, id2);
            
            Assert.AreEqual(id1, edgeId.Vertex1Id);
            Assert.AreEqual(id2, edgeId.Vertex2Id);
            
        }
        
        [Test]
        [Description("Verifies that an exception is thrown when " +
                     "passing a null IEdgeId to DeleteEdge()")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullEdgeIdDeletionTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            graph.DeleteEdge(null);
        }
        
        [Test]
        [Description("Verifies that false is returned " +
                     "when an unknown IEdgeId is provided")]
        public void UnknownEdgeIdDeletionTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId id = new BaseEdgeId(new BaseVertexId(), new BaseVertexId());
            
            Assert.False(graph.DeleteEdge(id));
        }
        
        [Test]
        [Description("Verifies that an edge is deleted "  +
                     "and the vertices associated with that " +
                     "edge remain intact.")]
        public void EdgeDeletionTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId goodId = graph.AddEdge(1, 1, 2);
            
            IVertexId id1 = goodId.Vertex1Id;
            IVertexId id2 = goodId.Vertex2Id;
            
            Assert.True(graph.DeleteEdge(goodId));
            Assert.AreEqual(1, graph.GetVertexData(id1));
            Assert.AreEqual(2, graph.GetVertexData(id2));
            
        }
                        
        [Test]
        [Description("Verifies that false is returned when " +
                     "trying to delete an unknown vertex")]
        public void UnknownVertexIdDeleteTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            Assert.False(graph.DeleteVertex(new BaseVertexId()));
            
        }
        
        [Test]
        [Description("Verifies that a valid edge data is return " +
                     "with a good IEdgeId")]
        public void GetEdgeDataTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId id = graph.AddEdge(2, 1,1);
            
            Assert.AreEqual(2,graph.GetEdgeData(id));
        }
        
        [Test]
        [Description("Verifies that a vertex and associated edges are "+
                     "deleted.")]
        public void DeleteVertexTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            //Create vertices
            IVertexId a = graph.AddVertex(2);
            IVertexId b = graph.AddVertex(3);
            IVertexId c = graph.AddVertex(4);
            IVertexId d = graph.AddVertex(5);
            
            IEdgeId aTob = graph.AddEdge(default(int), a, b);
            IEdgeId aTod = graph.AddEdge(default(int), a, d);
            IEdgeId bToc = graph.AddEdge(default(int), b, c);
            IEdgeId bTod = graph.AddEdge(default(int), b, d);
            IEdgeId cTod = graph.AddEdge(default(int), c, d);
            
            //Delete vertex b.  should remove edges, aToB, bToc, bTod.
            Assert.True(graph.DeleteVertex(b));
            Assert.False(graph.DeleteEdge(aTob));
            Assert.False(graph.DeleteEdge(bToc));
            Assert.False(graph.DeleteEdge(bTod));
            
        }
        
        [Test]
        [Description("Verifies that an exception is thrown " +
                     "if a null IVertexId is provided")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullVertexIdEdgeListTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            //Create vertices
            IVertexId a = graph.AddVertex(2);
            IVertexId b = graph.AddVertex(3);
            IVertexId c = graph.AddVertex(4);
            IVertexId d = graph.AddVertex(5);
            
            IEdgeId aTob = graph.AddEdge(default(int), a, b);
            IEdgeId aTod = graph.AddEdge(default(int), a, d);
            IEdgeId bToc = graph.AddEdge(default(int), b, c);
            IEdgeId bTod = graph.AddEdge(default(int), b, d);
            IEdgeId cTod = graph.AddEdge(default(int), c, d);
            
            IList<IEdgeId> edgeList = graph.GetEdgeList(null);
            
        }
        
        [Test]
        [Description("Verifies that an empty edge is returned " +
                     "if an unknown IVertexId is provided.")]
        public void UnknownIVertexIdEdgeListTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            //Create vertices
            IVertexId a = graph.AddVertex(2);
            IVertexId b = graph.AddVertex(3);
            IVertexId c = graph.AddVertex(4);
            IVertexId d = graph.AddVertex(5);
            
            IEdgeId aTob = graph.AddEdge(default(int), a, b);
            IEdgeId aTod = graph.AddEdge(default(int), a, d);
            IEdgeId bToc = graph.AddEdge(default(int), b, c);
            IEdgeId bTod = graph.AddEdge(default(int), b, d);
            IEdgeId cTod = graph.AddEdge(default(int), c, d);
            
            IList<IEdgeId> edgeList = graph.GetEdgeList(new BaseVertexId());
            
            Assert.AreEqual(0, edgeList.Count);
        }
        
        [Test]
        [Description("Verifies that an edge list is returned " +
                     "a known IVertexId")]
        public void EdgeListTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            //Create vertices
            IVertexId a = graph.AddVertex(2);
            IVertexId b = graph.AddVertex(3);
            IVertexId c = graph.AddVertex(4);
            IVertexId d = graph.AddVertex(5);
            
            IEdgeId aTob = graph.AddEdge(default(int), a, b);
            IEdgeId aTod = graph.AddEdge(default(int), a, d);
            IEdgeId bToc = graph.AddEdge(default(int), b, c);
            IEdgeId bTod = graph.AddEdge(default(int), b, d);
            IEdgeId cTod = graph.AddEdge(default(int), c, d);
            
            IList<IEdgeId> edgeList = graph.GetEdgeList(b);
            IList<IEdgeId> singleEdgeList = graph.GetEdgeList(c);
            
            Assert.AreEqual(2, edgeList.Count);
            Assert.AreEqual(1, singleEdgeList.Count);
            
            IList<IEdgeId> expectedCollection = new List<IEdgeId>();
            expectedCollection.Add(bToc);
            expectedCollection.Add(bTod);
            
            IList<IEdgeId> expectedCollection2 = new List<IEdgeId>();
            expectedCollection2.Add(cTod);
            
            CollectionAssert.AreEquivalent(expectedCollection, edgeList);
            CollectionAssert.AreEquivalent(expectedCollection2, singleEdgeList);
        }
        
        [Test]
        [Description("Verifies that an exception is thrown " + 
                     "when a null IEdgeId is passed during "  +
                     "ReplaceEdge()")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullIEdgeIdReplacementTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId goodId = graph.AddEdge(default(int), 1, 1);
            
            bool result = graph.ReplaceEdge(null, default(int));
        }
        
        [Test]
        [Description("Verifies that false is returned " +
                     "when an unknown IEdgeId is passed to " +
                     "ReplaceEdge()")]
        public void UnknownIEdgeIdReplacementTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId goodId = graph.AddEdge(default(int), 1, 1);
            IEdgeId badId = new BaseEdgeId(new BaseVertexId(), new BaseVertexId());
            
            Assert.False(graph.ReplaceEdge(badId, 1));
        }
        
        [Test]
        [Description("Verifies that true is returned " +
                     "when a known IEdgeId is passed to " +
                     "ReplaceEdge()")]
        public void GoodIEdgeIdReplacementTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId goodId = graph.AddEdge(default(int), 1, 1);
            
            bool result = graph.ReplaceEdge(goodId, 1);
            
            Assert.True(result);
            Assert.AreEqual(1,graph.GetEdgeData(goodId));
        }
        
        [Test]
        [Description("Verifies that a vertex can have an edge " +
                     "to itself.")]
        public void VertexAddEdgeToSelfTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId id = graph.AddVertex(1);
            
            IEdgeId eid = graph.AddEdge(default(int), id,id);
            
            Assert.AreEqual(eid.Vertex1Id, id);
            Assert.AreEqual(eid.Vertex2Id, id);
        }
        
        [Test]
        [Description("Tests that when adding a solitary vertex to the graph " +
                     "the returned IVertexId can find the specified VertexData ")]
        public void AddVertexAndRetrieveTest()
        {
            
            IGraph<int, int> graph = DirectedGraph();
            IVertexId vertexId = graph.AddVertex(1);
            
            Assert.NotNull(vertexId);
            
            int result = graph.GetVertexData(vertexId);
            
            Assert.AreEqual(1,result);
        }
        
        [Test]
        [Description("Verifies a null vertexId throws an exception")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullVertexIdExceptionTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            
            int result = graph.GetVertexData(null);
        }
        
        [Test]
        [Description("Verifies that an unknown vertexId throws an " +
                     "returns the default value..")]
        [ExpectedException(typeof(ArgumentException))]
        public void UnknownVertexIdExceptionTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            
            IVertexId vertexId = new BaseVertexId();
            
            graph.GetVertexData(vertexId);
        }

        [Test]
        [Description("Vertifies that a null vertexId throws an " +
                     "exception when trying to replace vertex data.")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullVertexIdReplaceTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            
            IVertexId vertexId = graph.AddVertex(1);
            
            graph.ReplaceVertex(null, 5);
        }
        
        [Test]
        [Description("Verifies that an unknown vertexId returns false " +
                     "when trying to replace vertex data.")]
        public void UnknownVertexIdReplaceTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId id = graph.AddVertex(1);
            IVertexId vertexId = new BaseVertexId();
            
            Assert.False(graph.ReplaceVertex(vertexId, 5));
        }
        
        [Test]
        [Description("Verifies that a valid vertexId can be used to " +
                     "replace vertex data")]
        public void ValidVertexIdReplaceTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IVertexId id = graph.AddVertex(5);
            
            Assert.AreEqual(5, graph.GetVertexData(id));
            Assert.True(graph.ReplaceVertex(id, 6));
            Assert.AreEqual(6, graph.GetVertexData(id));
        }
        
        [Test]
        [Description("Verifies that a null IEdgeId throws an " +
                     "exception when trying to get edge data.")]
        [ExpectedException(typeof(ArgumentNullException))]
        public void NullEdgeIdTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            int result = graph.GetEdgeData(null);
        }
       
        [Test]
        [Description("Verifies that an unknown IEdgeId returns default(U) " +
                     " when trying to get edge data for a value type.")]
        public void UnknownEdgeIdTest()
        {
            IGraph<int, int> graph = DirectedGraph();
            IEdgeId badId = new BaseEdgeId(new BaseVertexId(), new BaseVertexId());
            
            Assert.AreEqual(0, graph.GetEdgeData(badId));
        }
        
        [Test]
        [Description("Verifies that an unknown IEdgeId returns default(U) " +
                     "when trying to get edge data for a reference type.")]
        public void UnknownEdgeIdReferenceTypeTest()
        {
            IGraph<String, String> graph = GraphFactory<String, String>.CreateGraph(GraphTypes.Directed);
            
            IEdgeId badId = new BaseEdgeId(new BaseVertexId(), new BaseVertexId());
            
            Assert.Null(graph.GetEdgeData(badId));
        }
        
        
        [Test]
        [Description("Verifies that a exception is thrown by the graph if " +
                     "when invalid GraphType flags are provided")]
        [ExpectedException(typeof(ArgumentException))]
        public void InvalidGraphTypeTest()
        {
            GraphTypes g = (GraphTypes.Undirected | GraphTypes.Directed);
            
            IGraph<int, int> graph = GraphFactory<int, int>.CreateGraph(g);
        }
    }
}
